﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Codeplex.Data.Internal
{
    internal static class AccessorCache
    {
        static readonly ConcurrentDictionary<Type, KeyIndexed<string, CompiledAccessor>>
            cache = new ConcurrentDictionary<Type, KeyIndexed<string, CompiledAccessor>>();

        public static KeyIndexed<string, CompiledAccessor> Lookup(Type targetType)
        {
            var accessors = cache.GetOrAdd(targetType, target =>
            {
                var props = target.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty)
                    .Select(pi => new CompiledAccessor(pi));

                var fields = target.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.SetField)
                  .Select(fi => new CompiledAccessor(fi));

                return KeyIndexed<string, CompiledAccessor>.Create(props.Concat(fields), a => a.MemberName, a => a);
            });

            return (KeyIndexed<string, CompiledAccessor>)accessors;
        }
    }
}